package Olivia.olivia3d.shadow
{
	import Olivia.olivia3d.light.OLight;
	import Olivia.olivia3d.model.ms3d.MsGroup;
	import Olivia.olivia3d.model.ms3d.MsMaterial;
	import Olivia.olivia3d.model.ms3d.TempSimplifyModel;
	import Olivia.olivia3d.render.RenderManager;
	import Olivia.olivia3d.shader.FragmentShader;
	import Olivia.olivia3d.shader.VertexShader;
	import Olivia.olivia3d.vo.Ms3dVo;
	import Olivia.olivia3d.vo.Stage3DVo;
	
	import flash.display.Bitmap;
	import flash.display3D.Context3D;
	import flash.display3D.Context3DProgramType;
	import flash.display3D.Context3DTextureFormat;
	import flash.display3D.Context3DVertexBufferFormat;
	import flash.display3D.IndexBuffer3D;
	import flash.display3D.VertexBuffer3D;
	import flash.display3D.textures.Texture;
	import flash.events.EventDispatcher;
	import flash.geom.Matrix3D;
	import flash.geom.Point;
	import flash.geom.Vector3D;

	public class ShadowMap extends EventDispatcher
	{
		private static var _self:ShadowMap;
		public static function get ins():ShadowMap
		{
			if(!_self){
				_self = new ShadowMap();
			}
			return _self;
		}
		
		public var tsize:int = 2048;
		private var _shadowText:Texture;
		private var _s3dvo:Stage3DVo;
		
		public function ShadowMap()
		{
			
		}
		
		public function creatShadowDepth(s3dvo:Stage3DVo):Texture
		{
			_s3dvo = s3dvo;
			_shadowText = _s3dvo.context3D.createTexture(tsize,tsize,Context3DTextureFormat.BGRA, true);
			//set light matrix
			setLightMatrix();
			//render models in shadow map
			_s3dvo.context3D.setRenderToTexture(_shadowText,true,4,0);
			_s3dvo.context3D.clear(.3,.3,.3,1);
			for each(var model:Ms3dVo in _s3dvo.models){	
				//create model indexbuffer
				if(!model.initGroupIdx){
					TempSimplifyModel.createMs3dIndexBuffer(s3dvo,model);
					model.initProgram3D(s3dvo.context3D);
				}
				//clear vertex and texture
				_s3dvo.clearBufferAndTexture();
				//upload agal
				upload(model,model.type);			
			}
			return _shadowText;
		}
		
		private function upload(model:Ms3dVo, type:int):void
		{
			// TODO Auto Generated method stub
			var vertexes:VertexBuffer3D = _s3dvo.context3D.createVertexBuffer(model.vertexData.length/model.dataPerVertex, 
					model.dataPerVertex);
			vertexes.uploadFromVector(
				model.vertexData,
				0,
				model.vertexData.length/model.dataPerVertex);
			//va0 is position
			_s3dvo.context3D.setVertexBufferAt(0, vertexes, 0, Context3DVertexBufferFormat.FLOAT_3);
			
			//trianles indexList
//			var indexList:IndexBuffer3D = _s3dvo.context3D.createIndexBuffer(model.triangleData.length);
//			indexList.uploadFromVector(model.triangleData,0,model.triangleData.length);
			
			//set program contants
			setProgramContants(model,type);
			if(type==Ms3dVo.BaseType){
				//agal
				_s3dvo.setAgal(model.shadowPro3D);
			}else if(type==Ms3dVo.AnimType){
				var bonesVector:Vector.<Number> = model.getBoneVector(5);
				var bones:VertexBuffer3D = _s3dvo.context3D.createVertexBuffer(bonesVector.length/4,4);
				bones.uploadFromVector(
					bonesVector,
					0,
					bonesVector.length/4);
				//va3 is boneid
				_s3dvo.context3D.setVertexBufferAt(3, bones, 0, Context3DVertexBufferFormat.FLOAT_4);
				//get model fps born matrix
				getModelAnimotionMatrix(model);
//				//uv
//				_s3dvo.context3D.setVertexBufferAt(2, vertexes, 4, Context3DVertexBufferFormat.FLOAT_2);	//va2 is uv
//				var texture:Texture = _s3dvo.context3D.createTexture(bm.bitmapData.width,
//					bm.bitmapData.height,
//					Context3DTextureFormat.BGRA,
//					true);
//				texture.uploadFromBitmapData(bm.bitmapData);
//				_s3dvo.context3D.setTextureAt(0, texture);
				//agal
				_s3dvo.setAgal(model.shadowPro3D);
			}
			//render group
			renderGroup(_s3dvo.context3D,model);
		}
		
		private function renderGroup(context3D:Context3D,msvo:Ms3dVo):void
		{
			for each(var g:MsGroup in msvo.groupData){
				context3D.drawTriangles(g.indexBuffer);
			}
		}
		
		private function getModelAnimotionMatrix(model:Ms3dVo):void
		{
			// TODO Auto Generated method stub
			_s3dvo.context3D.setProgramConstantsFromVector(
				Context3DProgramType.VERTEX,
				4,
				Vector.<Number>([1,2,0,0]));
			_s3dvo.context3D.setProgramConstantsFromVector(
				Context3DProgramType.VERTEX,
				5,
				model.getJointDataThisFrame());
		}
		
		private function setProgramContants(model:Ms3dVo,type:int):void
		{
			// TODO Auto Generated method stub		
			//vc
			_s3dvo.context3D.setProgramConstantsFromMatrix(
				Context3DProgramType.VERTEX,
				0,
				OLight(_s3dvo.lights[0]).camera.getWorldViewProjMat(model.position),	//now this is only one light
				true);
			//fc
			_s3dvo.context3D.setProgramConstantsFromVector(
				Context3DProgramType.FRAGMENT,
				0,
				Vector.<Number>([
					1, 
					255, 
					65025, 
					160581375,
					1/255,			//bias
					1/255,			//bias
					1/255,			//bias
					0,				//bias
				]));
		}
		
		private function setLightMatrix():void
		{
			// TODO Auto Generated method stub
			var olight:OLight = new OLight();
			olight.camera.viewEye.x = 20;
			olight.camera.viewEye.y = 190;
			_s3dvo.lights.push(olight);
		}
	}
}